package com.ogawa.base.mqtt;

import android.annotation.SuppressLint;
import android.content.Context;
import android.text.TextUtils;

import com.blankj.utilcode.util.LogUtils;
import com.google.gson.Gson;
import com.jeremyliao.liveeventbus.LiveEventBus;
import com.ogawa.base.Constant.CommmandNum;
import com.ogawa.base.Constant.MqttConstant;
import com.ogawa.base.bean.PublishBean;
import com.ska.skautils.utilcode.util.SkaUtils;

import org.eclipse.paho.android.service.MqttAndroidClient;
import org.eclipse.paho.client.mqttv3.IMqttActionListener;
import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.IMqttToken;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import static com.ogawa.base.Constant.MqttConstant.LIVE_EVENT_BUS_KEY_RECEIVE_MESSAGE;
import static com.ogawa.base.Constant.MqttConstant.LIVE_EVENT_BUS_KEY_STATUS;

public class MQTTManager2 {
    private MqttAndroidClient mqttAndroidClient;
    private String clientId;//自定义

    private MqttConnectOptions mqttConnectOptions;

    private ScheduledExecutorService reconnectPool;//重连线程池

    private String curSn;
    private List<MqttReceiveListener> mMqttReceiveListeners = new ArrayList<>();

    private Gson mGson;
    private String mqttAccount, mqttPsw;


    private MQTTManager2() {
    }

    public static MQTTManager2 getInstance() {
        return MQTTManager2.InstanceHolder.INSTANCE;
    }
    private static class InstanceHolder {
        @SuppressLint("StaticFieldLeak")
        private static final MQTTManager2 INSTANCE = new MQTTManager2();
    }
    public String getCurSn() {
        return curSn;
    }

    public void setCurSn(String curSn) {
        this.curSn = curSn;
    }
    public void buildClient() {
        closeMQTT();//先关闭上一个连接

        buildMQTTClient();
    }

    private IMqttActionListener iMqttActionListener = new IMqttActionListener() {
        @Override
        public void onSuccess(IMqttToken asyncActionToken) {
            LogUtils.i("connect-"+"onSuccess");
            closeReconnectTask();
            subscribeToTopic();
        }

        @Override
        public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
            //connect-onFailure-MqttException (0) - java.net.UnknownHostException
            LogUtils.i("connect-"+ "onFailure-"+exception);
            startReconnectTask();
        }
    };

    private MqttCallback mqttCallback = new MqttCallback() {
        @Override
        public void connectionLost(Throwable cause) {
            //close-connectionLost-等待来自服务器的响应时超时 (32000)
            //close-connectionLost-已断开连接 (32109)
            LogUtils.i("close-"+"connectionLost-"+cause);
            if (cause != null) {//null表示被关闭
                startReconnectTask();
            }
        }

        @Override
        public void messageArrived(String topic, MqttMessage message) throws Exception {
//            String body = new String(message.getPayload());
//            LogUtils.i("messageArrived-"+message.getId()+"-"+body);
            if (mMqttReceiveListeners != null){
                for (int i = 0; i < mMqttReceiveListeners.size(); i++) {
                    mMqttReceiveListeners.get(i).onReceiveMqttMsg(topic,message);
                }
            }
        }

        @Override
        public void deliveryComplete(IMqttDeliveryToken token) {
            try {
                LogUtils.i("deliveryComplete-"+token.getMessage().toString());
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    };

    private void buildMQTTClient(){

        clientId = "android" + (int) ((Math.random() * 9 + 1) * 10000);
        LogUtils.e("initClient  clientId:" + clientId);

        mqttAndroidClient = new MqttAndroidClient(SkaUtils.getContext(), MqttConstant.HOST, clientId);
        mqttAndroidClient.setCallback(mqttCallback);
        mqttConnectOptions = new MqttConnectOptions();
        mqttConnectOptions.setCleanSession(true);
        mqttConnectOptions.setAutomaticReconnect(true);
        mqttConnectOptions.setConnectionTimeout(20);
        mqttConnectOptions.setKeepAliveInterval(20);
        mqttConnectOptions.setCleanSession(true);
        mqttConnectOptions.setMaxInflight(10);
        mGson = new Gson();




        doClientConnection();
    }
    public void setMqttMsg(String mqttAccount, String mqttPsw) {
        this.mqttAccount = mqttAccount;
        this.mqttPsw = mqttPsw;
    }

    private synchronized void startReconnectTask(){
        if (reconnectPool != null)return;
        reconnectPool = Executors.newScheduledThreadPool(1);
        reconnectPool.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                doClientConnection();
            }
        } , 0 , 5*1000 , TimeUnit.MILLISECONDS);
    }

    private synchronized void closeReconnectTask(){
        if (reconnectPool != null) {
            reconnectPool.shutdownNow();
            reconnectPool = null;
        }
    }

    /**
     * 连接MQTT服务器
     */
    private synchronized void doClientConnection() {
        if (TextUtils.isEmpty(mqttAccount) || TextUtils.isEmpty(mqttPsw)) {
            LogUtils.e("账号密码空退出");
            return ;
        }
        mqttConnectOptions.setUserName(mqttAccount);
        mqttConnectOptions.setPassword(mqttPsw.toCharArray());
        if (!mqttAndroidClient.isConnected()) {
            try {
                mqttAndroidClient.connect(mqttConnectOptions, null, iMqttActionListener);
                LogUtils.d("mqttAndroidClient-connecting-"+mqttAndroidClient.getClientId());
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    }

    private void subscribeToTopic() {//订阅之前会取消订阅，避免重连导致重复订阅
        try {
            String registerTopic = "cmd/up/"+curSn;//自定义
            String controlTopic = "cmd/back/"+curSn+"/"+clientId;//自定义
            String[] topicFilter=new String[]{registerTopic , controlTopic };
            int[] qos={2,2};
            mqttAndroidClient.unsubscribe(topicFilter, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
                    LogUtils.i("unsubscribe-"+"success");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
                    LogUtils.i("unsubscribe-"+"failed-"+exception);
                }
            });
            mqttAndroidClient.subscribe(topicFilter, qos, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {//订阅成功
                    LogUtils.e("订阅主题成功");
                    LiveEventBus.get(LIVE_EVENT_BUS_KEY_STATUS, Boolean.class).post(true);
                    LiveEventBus.get(LIVE_EVENT_BUS_KEY_RECEIVE_MESSAGE).post(LIVE_EVENT_BUS_KEY_RECEIVE_MESSAGE);
                    sendCommond(CommmandNum.mStatusRunning, "");
                    sendCommond(CommmandNum.mAllStatusQuery, "00");
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
//                    startReconnectTask();
                    LiveEventBus.get(LIVE_EVENT_BUS_KEY_STATUS,Boolean.class).post(false);
                }
            });

        } catch (MqttException ex) {
        }
    }

    public void sendCommond(String topicSep, String msg) {
        try {
            if (mqttAndroidClient == null)return;
            MqttMessage message = new MqttMessage();
            message.setPayload(msg.getBytes());
            String topic = "";//自定义
            mqttAndroidClient.publish(topic, message, null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
//                    TVLog.i("sendMQTT-"+"success:" + msg);
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
//                    startReconnectTask();
                    LogUtils.i("sendMQTT-"+"failed:" + msg);
                }
            });
        } catch (MqttException e) {
        }
    }

    private void publish(String topic, int qos, String content) {
        if (mqttAndroidClient == null)return;
        MqttMessage message = new MqttMessage(content.getBytes());
        message.setQos(qos);
        try {
            LogUtils.e("发送：" + topic + " : " + qos + " : " + content);
            mqttAndroidClient.publish(topic, message,null, new IMqttActionListener() {
                @Override
                public void onSuccess(IMqttToken asyncActionToken) {
//                    TVLog.i("sendMQTT-"+"success:" + msg);
                }

                @Override
                public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
//                    startReconnectTask();
                    LogUtils.i("sendMQTT-"+"failed:" );
                }
            });
        } catch (MqttException e) {
            e.printStackTrace();
        }

    }

    /**
     * 发布消息,带附加值
     *
     * @param func
     * @param model
     */
    public void publish(String func, String model, String addition) {
        PublishBean bean = new PublishBean();
        bean.setFunctionCode(func);
        bean.setModelValue(model);
        bean.setClientId(clientId);
        bean.setSn(curSn);
        bean.setAdditionalValue(addition);
        publish("cmd/down/" + curSn, 2, mGson.toJson(bean));
    }

    /**
     * 发布消息，不带附加值
     *
     * @param func
     * @param model
     */
    public void publish(String func, String model) {
        publish(func, model, null);
    }





    public void closeMQTT(){
        closeReconnectTask();
        if (mqttAndroidClient != null){
            try {
                mqttAndroidClient.unregisterResources();
                mqttAndroidClient.disconnect();
                LogUtils.i("closeMQTT-"+mqttAndroidClient.getClientId());
                mqttAndroidClient = null;
            } catch (MqttException e) {
                e.printStackTrace();
            }
        }
    }

    public void registeronReceiveMqttMsg(MqttReceiveListener callback) {
        if (!mMqttReceiveListeners.contains(callback)) {
            mMqttReceiveListeners.add(callback);
        }
    }

    public void unRegisteronReceiveMqttMsg(MqttReceiveListener callback) {
        mMqttReceiveListeners.remove(callback);
    }
}
